﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;

using System.Web.Script.Serialization;
using System.Text;
using System.Net;
using System.IO;

using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Plorx
{
    [ComVisibleAttribute(true)]
    public partial class MainForm : Form
    {
        private struct loc_struct
        {
            public string nick_name;
            public string disp_name;
            public string uid;
            public string avatar;
        }
        private Plorx plorx = null;
        private Progress progress = new Progress();
        private Dictionary<Dictionary<string, object>, List<loc_struct>> locations = new Dictionary<Dictionary<string, object>, List<loc_struct>>();
        private List<Dictionary<string, object>> locations_mod = new List<Dictionary<string, object>>();
        private List<Dictionary<string, object>> people = new List<Dictionary<string, object>>();
        private Thread work_thread = null;
        private bool cancelled = false;

        public MainForm()
        {
            InitializeComponent();

//            plorx.MakeAPICall(Timeline.getPublicPlurks("mistificator"));
//            plorx.MakeAPICall(Profile.getPublicProfile("mistificator"));
//            plorx.MakeAPICall(PlurkSearch.search("мстители"));
//            plorx.MakeAPICall(FriendsFans.getFriendsByOffset(plorx.user_id("mistificator")));
/*
            var _plurks = plorx.plurks;
            var _friends = plorx.friends;
            var _fans = plorx.fans;
            var _plurk_users = plorx.plurk_users;
            var _users = plorx.users;
            var _user = plorx.user;
            var _user_info = plorx.user_info;
            Log.Text = plorx.PrintAPIResult();
            var _locations = new List<string>();
*/

//            var _locations = new List<Dictionary<string, object>>();

            browser.ObjectForScripting = this;
            progress.cancelButton.Click += new EventHandler(cancelButton_Click);
            progress.label.Text = "Plorx is logging in";
            progress.Show(this);
            Enabled = false;
            plorx = new Plorx();
            plorx.FansEvent += new Plorx.FansEventHandler(plorx_FansEvent);
            plorx.FriendsEvent += new Plorx.FriendsEventHandler(plorx_FriendsEvent);
            DrawMap();
            Enabled = true;
            progress.Hide();
            boxName.Select();
        }

        void cancelButton_Click(object sender, EventArgs e)
        {
            if (work_thread == null)
            {
                return;
            }
            work_thread.Interrupt();
        }

        private delegate void SetProgressTextDelegate(string _text);
        private void SetProgressText(string _text)
        {
            progress.label.Text = _text;
        }
        private void plorx_FansEvent(Dictionary<string, object>[] _fans, int _count)
        {
            progress.label.BeginInvoke(new SetProgressTextDelegate(SetProgressText), "Plorx is searching for fans (" + _count + ")");
        }

        private void plorx_FriendsEvent(Dictionary<string, object>[] _friends, int _count)
        {
            progress.label.BeginInvoke(new SetProgressTextDelegate(SetProgressText), "Plorx is searching for friends (" + _count + ")");
        }

        private void UpdateMap()
        {
            cancelled = false;
            people.Clear();

            progress.cancelButton.Enabled = true;
            progress.progressBar.Value = 0;
            progress.Visible = false;
            progress.Show(this);
            Enabled = false;

            plorx.MakeAPICall(Profile.getPublicProfile(boxName.Text));
            if (plorx.user_info != null)
            {
                people.Add(plorx.user_info);
            }

            if (checkFans.Checked)
            {
                ThreadedExec(new ThreadStart(GetAllFans), "Plorx is searching for fans");       
                if (plorx.fans != null) people.AddRange(plorx.fans);
            }
            if (checkFriends.Checked)
            {
                ThreadedExec(new ThreadStart(GetAllFriends), "Plorx is searching for friends"); 
                if (plorx.friends != null) people.AddRange(plorx.friends);
            }
            ThreadedExec(new ThreadStart(GetAllPlaces), "Plorx is searching for places");
            ThreadedExec(new ThreadStart(BuildMap), "Plorx is building map");
            DrawMap(GoogleGeocode.ObjectToJSON(locations_mod));

            Enabled = true;
            progress.Hide();
            work_thread = null;
        }

        void DrawMap(string _location_json = "[]")
        {
/*
            if (cancelled)
            {
                return;
            }
 */
            string _google_map_js_api = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"initial-scale=1.0, user-scalable=no\" /><style type=\"text/css\">html { height: 100% } body { height: 100%; margin: 0px; padding: 0px } #map_canvas { height: 100% }</style><script type=\"text/javascript\" src=\"https://maps.google.com/maps/api/js?sensor=false\"> </script> <script type=\"text/javascript\">";
            _google_map_js_api += "var locations = " + _location_json + ";";
            _google_map_js_api += "function initialize() { var map = new google.maps.Map(document.getElementById(\"map_canvas\"), {zoom: 3, center: new google.maps.LatLng(30.0, 30.0, true), mapTypeId: google.maps.MapTypeId.TERRAIN}); var info = new google.maps.InfoWindow(); for (var i = 0; i < locations.length; i++) { var loc = locations[i]; var mrk = new google.maps.Marker({title: loc['text'], map: map, position: new google.maps.LatLng(loc['lat'], loc['lng'], true)}); setup_info(info, mrk, loc['link']); }} function setup_info(info, mrk, text) { google.maps.event.addListener(mrk, 'click', function() { info.setContent(text); info.open(mrk.getMap(), mrk); }); } google.maps.event.addDomListener(window, 'load', initialize);</script></head><body><div id=\"map_canvas\"></div></body></html>";
            browser.AllowNavigation = true;
            browser.Document.Write(_google_map_js_api);
            browser.Refresh(WebBrowserRefreshOption.Completely);
            browser.AllowNavigation = false;
            Log.Text = _google_map_js_api;
        }
      
        private void goButton_Click(object sender, EventArgs e)
        {
            UpdateMap();
            cancelled = false;
        }

        private void ThreadedExec(ThreadStart _ts, string _label_text = "", int _pb_value = -1)
        {
            progress.label.Text = _label_text;
            if (_pb_value >= 0)
            {
                progress.progressBar.Value = _pb_value;
            }
            work_thread = new Thread(_ts);
            work_thread.Start();
            while (work_thread.ThreadState != System.Threading.ThreadState.Stopped)
            {
                Application.DoEvents();
            }
        }

        private void GetAllFans()
        {
            try
            {
                if (cancelled)
                {
                    return;
                }
                plorx.GetAllFans(boxName.Text);
            }
            catch (ThreadInterruptedException)
            {
                cancelled = true;
            }
        }

        private void GetAllFriends()
        {
            try
            {
                if (cancelled)
                {
                    return;
                }
                plorx.GetAllFriends(boxName.Text);
            }
            catch (ThreadInterruptedException)
            {
                cancelled = true;
            }
        }

        private loc_struct FillLocation(Dictionary<string, object> _item)
        {
            loc_struct _loc_struct = new loc_struct();
            string _full_name = _item["full_name"] as string;
            _loc_struct.disp_name = _item["display_name"] as string;
            _loc_struct.nick_name = _item["nick_name"] as string;
            _loc_struct.uid = _item["uid"] as string;
            if (_loc_struct.uid == null || _loc_struct.uid.Length == 0)
            {
                _loc_struct.uid = Convert.ToString(_item["id"]);
            }
            if (Convert.ToInt64(_item["has_profile_image"]) == 1)
            {
                string _avatar = Convert.ToString(_item["avatar"]);
                if (_avatar == null || _avatar == "0")
                {
                    _loc_struct.avatar = "http://avatars.plurk.com/" + _loc_struct.uid + "-small.gif";
                }
                else
                {
                    _loc_struct.avatar = "http://avatars.plurk.com/" + _loc_struct.uid + "-small" + _avatar + ".gif";
                }
            }
            else
            {
                _loc_struct.avatar = "http://avatars.plurk.com/static/default-small.gif";
            }
            if (_loc_struct.nick_name == _loc_struct.disp_name)
            {
                _loc_struct.disp_name = _full_name;
            }
            else if (_loc_struct.disp_name == null || _loc_struct.disp_name.Length == 0)
            {
                if (_full_name != null && _full_name.Length > 0)
                {
                    _loc_struct.disp_name = _full_name;
                }
                else
                {
                    _loc_struct.disp_name = _loc_struct.nick_name;
                }
            }
            return _loc_struct;
        }
        private void GetAllPlaces()
        {
            try
            {
                if (cancelled)
                {
                    return;
                }
                locations.Clear();
                int _i = 0;
                foreach (var _item in people)
                {
                    var _location = GoogleGeocode.Location(_item["location"] as string);
                    if (_location != null)
                    {
                        bool _found = false;
                        foreach (var _loc in locations)
                        {
                            if ((Convert.ToDouble(_loc.Key["lat"]) == Convert.ToDouble(_location["lat"])) && (Convert.ToDouble(_loc.Key["lng"]) == Convert.ToDouble(_location["lng"])))
                            {
                                locations[_loc.Key].Add(FillLocation(_item));
                                _found = true;
                                break;
                            }
                        }
                        if (!_found)
                        {
                            locations[_location] = new List<loc_struct>();
                            locations[_location].Add(FillLocation(_item));
                        }
                    }
                    _i++;
                    progress.label.BeginInvoke(new SetProgressTextDelegate(SetProgressText), "Plorx is searching for places (" + _i + "/" + people.Count + ")");
                }
            }
            catch (ThreadInterruptedException)
            {
                cancelled = true;
            }
        }
        private void BuildMap()
        {
            try
            {
                /*
                if (cancelled)
                {
                    return;
                }
                */ 
                locations_mod.Clear();
                foreach (var _item in locations)
                {
                    var _item_mod = _item.Key;
                    _item_mod["text"] = _item_mod["formatted_address"] + "\r\n________________\r\n";
                    _item_mod["link"] = "<h3>" + _item_mod["formatted_address"] + "</h3>";
                    foreach (var _par in _item.Value)
                    {
                        _item_mod["text"] += _par.nick_name + " (" + _par.disp_name + ")\r\n";
                        _item_mod["link"] += 
                            "<a onclick=\"window.external.LinkOpen('http://plurk.com/" + _par.nick_name + "');\" href=\"http://plurk.com/" + _par.nick_name + "\">" +
                            "<img src=\"" + _par.avatar + "\" />" + _par.nick_name + " (" + _par.disp_name + ")" + "</a><br />";
                    }
                    locations_mod.Add(_item_mod);
                }
            }
            catch (ThreadInterruptedException)
            {
                cancelled = true;
            }
        }

        private void checkFriends_CheckedChanged(object sender, EventArgs e)
        {
            goButton.Enabled = checkFans.Checked || checkFriends.Checked;
        }

        private void checkFans_CheckedChanged(object sender, EventArgs e)
        {
            goButton.Enabled = checkFans.Checked || checkFriends.Checked;
        }

        public void LinkOpen(string _link)
        {
            Process.Start(_link);
        }

        private void refreshButton_Click(object sender, EventArgs e)
        {
            DrawMap(GoogleGeocode.ObjectToJSON(locations_mod));
        }
    }
}
